#pragma once
#include <functional>
#include <type_traits>
#include <stdexcept>
#include <unordered_map>


/*使用示例
 *std::string str = "str";

JudgmentExecutionTool::JudgmentExecution<bool,void,int>  judgmentExecution;
judgmentExecution.setJudgmentData(true,  std::function<void(int)>([&](int i) {
    std::cout << "ture =" << i<< std::endl;
    std::cout << str << std::endl;
}));


judgmentExecution.setJudgmentData(false,std::function<void(int)> ([&](int i) {
    std::cout << "false=" <<i <<std::endl;
    std::cout << str << std::endl;
}));


judgmentExecution.runBYJudgmentConditionValue(3!=3,444);*/


namespace JudgmentExecutionTool {


    /**
     * 向前声明JudgmentExecution防止JudgmentData的友元类类型识别不了
     * @tparam JUDGMENT_TYPE
     * @tparam RETURN_TYPE
     * @tparam ARGS
     */
    template<typename JUDGMENT_TYPE, typename RETURN_TYPE, typename ...ARGS>
    class JudgmentExecution;



    /**
     *
     * @tparam JUDGMENT_TYPE  判定格式(if语句)
     * @tparam RETURN_TYPE 回调函数返回类型
     * @tparam ARGS 回调函数参数
     */
    template<typename JUDGMENT_TYPE, typename RETURN_TYPE ,typename ...ARGS>
    class JudgmentData {

    private:
        JUDGMENT_TYPE m_judgmentConditionValue;
        std::function<RETURN_TYPE(ARGS...)> m_executionFunc;

    private:
        /**
         * 私有化构造函数
         */
        JudgmentData() = default;


        /**
         *
         * @param judgmentConditionValue
         * @param executionFunc
         */
        JudgmentData(JUDGMENT_TYPE judgmentConditionValue, const std::function<RETURN_TYPE(ARGS...)>& executionFunc) {
            this->m_judgmentConditionValue = judgmentConditionValue;
            this->m_executionFunc = executionFunc;

        }


        /**
         * 私有化析构函数
         */
        ~JudgmentData() {

        }

    public:


        /**
         *
         * @return
         */
        JUDGMENT_TYPE getJudgmentConditionVlue() const  {
            return this->m_judgmentConditionValue;
        }

        /**
         *
         * @return
         */
        std::function<RETURN_TYPE(ARGS...)> getExecutionFunc() const {

            return this->m_executionFunc;
        }


        //设置友元类
        friend class JudgmentExecution<JUDGMENT_TYPE, RETURN_TYPE, ARGS...>;

    };


    /**
     *
     * @tparam JUDGMENT_TYPE
     * @tparam RETURN_TYPE
     * @tparam ARGS
     */
    template<typename JUDGMENT_TYPE,typename RETURN_TYPE ,typename ...ARGS>
    class JudgmentExecution {

        private:

        std::unordered_map<JUDGMENT_TYPE ,JudgmentData<JUDGMENT_TYPE,RETURN_TYPE,ARGS...>*> m_judgmentDatasMap;



        public:


        JudgmentExecution() {


        }


        /**
         *
         * @param judgmentConditionValue  判定条件值
         * @param executionFunc 传入判定条件值对应的执行函数
         */
        void setJudgmentData(JUDGMENT_TYPE judgmentConditionValue,const std::function<RETURN_TYPE(ARGS...)>& executionFunc ) {
            JudgmentData<JUDGMENT_TYPE,RETURN_TYPE,ARGS...>* judgmentData =
                new JudgmentData<JUDGMENT_TYPE,RETURN_TYPE,ARGS...>(judgmentConditionValue,executionFunc);


            this->m_judgmentDatasMap[judgmentConditionValue] = judgmentData;
        }


        /**
         *
         * @param judgmentConditionValue
         * @param args
         * @return
         */
        RETURN_TYPE runBYJudgmentConditionValue(JUDGMENT_TYPE judgmentConditionValue,ARGS... args) {
            if (this->m_judgmentDatasMap.count(judgmentConditionValue)< 1) throw std::runtime_error("执行函数未初始化");
            std::function<RETURN_TYPE(ARGS...)> executionFunc = this->m_judgmentDatasMap[judgmentConditionValue]->getExecutionFunc();

            return executionFunc(args...);
        }


        /**
         * 析构函数
         */
        ~JudgmentExecution() {
            //删除m_judgmentDatasMap的堆数据
            typename std::unordered_map<JUDGMENT_TYPE ,JudgmentData<JUDGMENT_TYPE,RETURN_TYPE,ARGS...>*>::iterator it =
                this->m_judgmentDatasMap.begin();

            while (it != this->m_judgmentDatasMap.end()) {
                delete it->second;
            }
        }



     };






}
